using System;
using System.Diagnostics;
using System.Collections.Generic;

namespace Dida
{
	public class InteractionRegister
	{
		Dictionary<Type, HashSet<InteractionDesc>> interactionDescs = new Dictionary<Type, InteractionDesc>();

		public void RegisterInteraction<Interactor1Type,Interactor2Type>(InteractionHandler<Interactor1Type,Interactor2Type> handler,int priority)
			where Interactor1Type : Actor
			where Interactor2Type : Actor
		{
			InteractionDesc desc = new InteractionDesc();
			desc.interactor1Type = typeof(Interactor1Type);
			desc.interactor2Type = typeof(Interactor2Type);
			desc.priority = priority;
			desc.handler = handler;

			AddDesc(desc.interactor1Type, desc);
			AddDesc(desc.interactor2Type, desc);
		}

		private void AddDesc(Type type,InteractionDesc desc)
		{
			HashSet<InteractionDesc> slot;
			if (!interactionDescs.TryGetValue(type, out slot))
			{
				slot = new HashSet<InteractionDesc>();
				interactionDescs.Add(type, slot);
			}

			slot.Add(desc);
		}

		public Delegate GetInteractionHandler(object interactor1, object interactor2)
		{
			Type type1 = interactor1.GetType();
			Type type2 = interactor2.GetType();

			HashSet<InteractionDesc> interactionsForType1 = FindInteractionsForType(type1);
			HashSet<InteractionDesc> interactionsForType2 = FindInteractionsForType(type2);

			HashSet<InteractionDesc> handlers = interactionsForType1.GetIntersection(interactionsForType2);
		}

		private HashSet<InteractionDesc> FindInteractionsForType(Type type)
		{
			HashSet<InteractionDesc> ret = null;
			for (Type curType = type; curType != typeof(Actor); curType = curType.BaseType)
			{
				HashSet<InteractionDesc> slot;
				if (interactionDescs.TryGetValue(curType, out slot))
				{
					ret = slot;
					break;
				}
			}

			// also check the interfaces

			return ret;
		}

		public delegate void InteractionHandler<Interactor1Type, Interactor2Type>(Interactor1Type interactor1, Interactor2Type interactor2);

		class InteractionDesc
		{
			public Type interactor1Type;
			public Type interactor2Type;
			public int priority;

			public Delegate handler;
		};
	}
}